
<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />

    <title>Writing Leo scripts in Python &#8212; Leo 6.7.2 documentation</title>
    <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="_static/classic.css" />
    <link rel="stylesheet" type="text/css" href="_static/custom.css" />
    
    <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
    <script src="_static/jquery.js"></script>
    <script src="_static/underscore.js"></script>
    <script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
    <script src="_static/doctools.js"></script>
    <script src="_static/sphinx_highlight.js"></script>
    
    <script src="_static/sidebar.js"></script>
    
    <link rel="index" title="Index" href="genindex.html" />
    <link rel="search" title="Search" href="search.html" />
    <link rel="next" title="Useful Tips" href="tutorial-tips.html" />
    <link rel="prev" title="Creating Documents from Outlines" href="tutorial-rst3.html" /> 
  </head><body>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="tutorial-tips.html" title="Useful Tips"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="tutorial-rst3.html" title="Creating Documents from Outlines"
             accesskey="P">previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="leo_toc.html">Leo 6.7.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="tutorial.html" accesskey="U">Leo’s Tutorials</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">Writing Leo scripts in Python</a></li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <section id="writing-leo-scripts-in-python">
<h1>Writing Leo scripts in Python<a class="headerlink" href="#writing-leo-scripts-in-python" title="Permalink to this heading">¶</a></h1>
<p>This chapter tells how to write <strong>Leo scripts</strong>, Python scripts run from any Leo node. This chapter is intended for those fairly comfortable with Python scripting. If you are not, please study the excellent <a class="reference external" href="http://docs.python.org/2/tutorial/">Python Tutorial</a>. Jacob Peck has written a more <a class="reference external" href="http://blog.suspended-chord.info/2014/01/28/intro-to-leo-scripting/">informal scripting tutorial</a>.</p>
<p>Three predefined symbols, <strong>c</strong>, <strong>g</strong>, and <strong>p</strong> give Leo scripts easy access to all the data in the outline. These symbols also allow Leo scripts to execute any code in Leo’s own codebase.</p>
<p><strong>Positions</strong> and <strong>vnodes</strong> are the foundation of Leo scripting. leo/core/leoNodes.py defines the corresponding Position and VNode classes. These classes provide access to all outline data and allow Leo scripts to create and change outlines.</p>
<p><strong>Further study</strong>: The <a class="reference external" href="cheatsheet.html#scripting">scripting portion</a> of <a class="reference external" href="cheatsheet.html">Leo’s cheat sheet</a> contains more information about scripting.</p>
<div class="contents local topic" id="contents">
<p class="topic-title">Contents</p>
<ul class="simple">
<li><p><a class="reference internal" href="#hello-world" id="id2">Hello world</a></p></li>
<li><p><a class="reference internal" href="#create-outline-nodes" id="id3">Create outline nodes</a></p></li>
<li><p><a class="reference internal" href="#generate-an-output-file-from-nodes" id="id4">Generate an output file from nodes</a></p></li>
<li><p><a class="reference internal" href="#predefined-symbols-c-g-and-p" id="id5">Predefined symbols: c, g, and p</a></p></li>
<li><p><a class="reference internal" href="#positions-and-vnodes" id="id6">Positions and vnodes</a></p></li>
<li><p><a class="reference internal" href="#generators" id="id7">Generators</a></p></li>
<li><p><a class="reference internal" href="#wrappers-vs-widgets" id="id8">wrappers vs. widgets</a></p></li>
<li><p><a class="reference internal" href="#summary" id="id9">Summary</a></p></li>
</ul>
</div>
<section id="hello-world">
<h2><a class="toc-backref" href="#id2">Hello world</a><a class="headerlink" href="#hello-world" title="Permalink to this heading">¶</a></h2>
<p id="index-0">Here is the obligatory “Hello World!” script:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="s1">&#39;Hello World!&#39;</span><span class="p">)</span> <span class="c1"># g.es prints all its arguments to the log pane.</span>
</pre></div>
</div>
<p>In more detail:</p>
<ol class="arabic simple">
<li><p>Create a node anywhere in the outline.</p></li>
<li><p>Put g.es(‘hello, world!’) in the node’s body text.</p></li>
<li><p>Select the node and type Ctrl-B.</p></li>
</ol>
<p><strong>Important</strong> If text is selected, execute-script executes only the selected text. If you are in LeoDocs.leo, you can run the script from this node.</p>
</section>
<section id="create-outline-nodes">
<h2><a class="toc-backref" href="#id3">Create outline nodes</a><a class="headerlink" href="#create-outline-nodes" title="Permalink to this heading">¶</a></h2>
<p><strong>p.b</strong> is the body text associated with position p. Similarly, <strong>p.h</strong> is p’s headline.
p.b and p.h are python properties, so you can assign to p.b and p.h.</p>
<p>This script creates an outline node as the last top-level node:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">p</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">lastTopLevel</span><span class="p">()</span><span class="o">.</span><span class="n">insertAfter</span><span class="p">()</span>
<span class="n">p</span><span class="o">.</span><span class="n">h</span> <span class="o">=</span> <span class="s1">&#39;my new node&#39;</span>
<span class="n">c</span><span class="o">.</span><span class="n">redraw</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="c1"># Selects the new node.</span>
</pre></div>
</div>
<p>This script creates multiple nodes, with different headlines:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">parent</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">lastTopLevel</span><span class="p">()</span><span class="o">.</span><span class="n">insertAfter</span><span class="p">()</span>
<span class="n">parent</span><span class="o">.</span><span class="n">h</span> <span class="o">=</span> <span class="s1">&#39;New nodes&#39;</span>
<span class="n">table</span> <span class="o">=</span> <span class="p">(</span>
    <span class="p">(</span><span class="s1">&#39;First node&#39;</span><span class="p">,</span> <span class="s1">&#39;Body text for first node&#39;</span><span class="p">),</span>
    <span class="p">(</span><span class="s1">&#39;Node 2&#39;</span><span class="p">,</span>     <span class="s1">&#39;Body text for node 2&#39;</span><span class="p">),</span>
    <span class="p">(</span><span class="s1">&#39;Last Node&#39;</span><span class="p">,</span>  <span class="s1">&#39;Body text for last node</span><span class="se">\n</span><span class="s1">Line 2&#39;</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">headline</span><span class="p">,</span> <span class="n">body</span> <span class="ow">in</span> <span class="n">table</span><span class="p">:</span>
    <span class="n">child</span> <span class="o">=</span> <span class="n">parent</span><span class="o">.</span><span class="n">insertAsLastChild</span><span class="p">()</span>
    <span class="n">child</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="n">body</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span> <span class="c1"># Ensure exactly one trailing newline.</span>
    <span class="n">child</span><span class="o">.</span><span class="n">h</span> <span class="o">=</span> <span class="n">headline</span>
<span class="n">c</span><span class="o">.</span><span class="n">selectPosition</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span> <span class="c1"># Another way to select nodes.</span>
<span class="n">c</span><span class="o">.</span><span class="n">redraw</span><span class="p">()</span>
</pre></div>
</div>
<p>This script creates a node containing today’s date in the body text:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">time</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">lastTopLevel</span><span class="p">()</span><span class="o">.</span><span class="n">insertAfter</span><span class="p">()</span>
<span class="n">p</span><span class="o">.</span><span class="n">h</span> <span class="o">=</span> <span class="s2">&quot;Today&#39;s date&quot;</span>
<span class="n">p</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%Y/%m/</span><span class="si">%d</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">redraw</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="generate-an-output-file-from-nodes">
<h2><a class="toc-backref" href="#id4">Generate an output file from nodes</a><a class="headerlink" href="#generate-an-output-file-from-nodes" title="Permalink to this heading">¶</a></h2>
<p>The script writes the body text of the presently selected node to ~/leo_output_file.txt and then prints it to the log pane:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">fn</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">os_path_finalize_join</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">app</span><span class="o">.</span><span class="n">homeDir</span><span class="p">,</span> <span class="s1">&#39;leo_output_file.txt&#39;</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">fn</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">p</span><span class="o">.</span><span class="n">b</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">fn</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
        <span class="n">g</span><span class="o">.</span><span class="n">es</span><span class="p">(</span><span class="n">line</span><span class="o">.</span><span class="n">rstrip</span><span class="p">())</span>
</pre></div>
</div>
</section>
<section id="predefined-symbols-c-g-and-p">
<h2><a class="toc-backref" href="#id5">Predefined symbols: c, g, and p</a><a class="headerlink" href="#predefined-symbols-c-g-and-p" title="Permalink to this heading">¶</a></h2>
<p id="index-1">The execute-script command predefines the symbols c, g, and p.</p>
<p>c is the <strong>commander</strong> of the outline containing the script. Commanders are instances of the Commands class, defined in leoCommands.py. Commanders provide access to all outline data <em>and</em> all of Leo’s source code.</p>
<p>g is Leo’s <strong>leo.core.leoGlobals</strong> containing many useful functions, including g.es.</p>
<p>p is the <strong>position</strong> of the presently selected node. Positions represent nodes at a particular location of an outline. Because of clones, the <em>same</em> node may appear at multiple positions in an outline. <strong>c.p</strong> is the outline’s presently selected position.</p>
</section>
<section id="positions-and-vnodes">
<h2><a class="toc-backref" href="#id6">Positions and vnodes</a><a class="headerlink" href="#positions-and-vnodes" title="Permalink to this heading">¶</a></h2>
<p>A <strong>position</strong> represents an outline node at a <em>specific position</em> in the outline. Positions provide methods to insert, delete and move outline nodes. The <a class="reference external" href="cheatsheet.html#scripting">scripting portion</a> of <a class="reference external" href="cheatsheet.html">Leo’s cheat sheet</a> lists the most important methods of the position class.</p>
<p>Because of clones, the <em>same</em> node may appear at <em>multiple positions</em> in the outline. A <strong>vnode</strong> represents the node’s data, which is shared by all positions referring to that node.</p>
<p>For any position p, <strong>p.b</strong> is the node’s body text, <strong>p.h</strong> is the node’s headline and <strong>p.u</strong> is the node’s <a class="reference external" href="customizing.html#adding-extensible-attributes-to-nodes-and-leo-files">user attributes</a>, and <strong>p.v</strong> is the position’s vnode. Similarly, for any vnode v, <strong>v.b</strong> is the node’s body text, <strong>v.h</strong> is the node’s headline and <strong>v.u</strong> is the node’s user attributes.</p>
</section>
<section id="generators">
<h2><a class="toc-backref" href="#id7">Generators</a><a class="headerlink" href="#generators" title="Permalink to this heading">¶</a></h2>
<p id="index-3">Commanders and positions define several <a class="reference external" href="https://wiki.python.org/moin/Generators">Python generators</a> to traverse (step through) an outline. The <a class="reference external" href="cheatsheet.html#scripting">scripting portion</a> of <a class="reference external" href="cheatsheet.html">Leo’s cheat sheet</a> lists all of Leo’s generators. For example, c.all_positions() traverses the outline in outline order.  The following prints a properly-indented list of all headlines:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">c</span><span class="o">.</span><span class="n">all_positions</span><span class="p">():</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="o">*</span><span class="n">p</span><span class="o">.</span><span class="n">level</span><span class="p">()</span><span class="o">+</span><span class="n">p</span><span class="o">.</span><span class="n">h</span><span class="p">)</span>
</pre></div>
</div>
<p id="index-4">Scripts may capture positions like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">aList</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">all_positions</span><span class="p">())</span>
</pre></div>
</div>
<p><strong>Warning</strong>: stored positions become invalid when outline changes. <strong>c.positionExists(p)</strong> is True if p is valid in c’s outline.</p>
<p><strong>New in Leo 5.5</strong>: All generators now yield <em>copies</em> of positions.</p>
</section>
<section id="wrappers-vs-widgets">
<h2><a class="toc-backref" href="#id8">wrappers vs. widgets</a><a class="headerlink" href="#wrappers-vs-widgets" title="Permalink to this heading">¶</a></h2>
<p>Leo’s Gui code is built on wrapper and widget classes. A <strong>widget</strong> is an actual Qt widget. A <strong>wrapper</strong> is an object whose API hides the details of the underlying gui <strong>text</strong> widgets. Leo’s core code usually uses wrappers, not raw widgets.</p>
<p>There is a back door for special cases. All wrapper classes define an official <code class="docutils literal notranslate"><span class="pre">widget</span></code> ivar (instance variable), so core or plugin code can gain access to the real Qt widget using <code class="docutils literal notranslate"><span class="pre">wrapper.widget</span></code>. Searching for <code class="docutils literal notranslate"><span class="pre">wrapper.widget</span></code> should find all gui-dependent snippets of code in Leo’s core.</p>
<p>Wrappers allow the same text-handling code to work regardless of whether the actual text widgets are a QTextBrowser or a QsciScintilla object. Without wrappers, all of Leo’s text-editing commands would have to know the details of the api of the actual Qt text widget!</p>
</section>
<section id="summary">
<h2><a class="toc-backref" href="#id9">Summary</a><a class="headerlink" href="#summary" title="Permalink to this heading">¶</a></h2>
<ul class="simple">
<li><p>execute-script predefines c, g, and p.</p></li>
<li><p>c is a commander, g is the leoGlobals module, and p is the current position.</p></li>
<li><p>Vnodes contain all outline data.</p></li>
<li><p>Positions provide easy access to vnodes.</p></li>
<li><p>Positions become invalid when outline nodes are inserted, deleted, or moved.</p></li>
<li><p>Generators visit all or parts of the outline, in a specified order.</p></li>
</ul>
<p>For more information, consult <a class="reference external" href="cheatsheet.html">Leo’s cheat sheet</a> and <a class="reference external" href="scripting-miscellany.html">Leo’s scripting miscellany</a></p>
</section>
</section>


            <div class="clearer"></div>
          </div>
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
            <p class="logo"><a href="leo_toc.html">
              <img class="logo" src="_static/LeoLogo.svg" alt="Logo"/>
            </a></p>
  <div>
    <h4>Previous topic</h4>
    <p class="topless"><a href="tutorial-rst3.html"
                          title="previous chapter">Creating Documents from Outlines</a></p>
  </div>
  <div>
    <h4>Next topic</h4>
    <p class="topless"><a href="tutorial-tips.html"
                          title="next chapter">Useful Tips</a></p>
  </div>
<div id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>
        </div>
<div id="sidebarbutton" title="Collapse sidebar">
<span>«</span>
</div>

      </div>
      <div class="clearer"></div>
    </div>
    <div class="related" role="navigation" aria-label="related navigation">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="tutorial-tips.html" title="Useful Tips"
             >next</a> |</li>
        <li class="right" >
          <a href="tutorial-rst3.html" title="Creating Documents from Outlines"
             >previous</a> |</li>
        <li class="nav-item nav-item-0"><a href="leo_toc.html">Leo 6.7.2 documentation</a> &#187;</li>
          <li class="nav-item nav-item-1"><a href="tutorial.html" >Leo’s Tutorials</a> &#187;</li>
        <li class="nav-item nav-item-this"><a href="">Writing Leo scripts in Python</a></li> 
      </ul>
    </div>
    <div class="footer" role="contentinfo">
        &#169; Copyright 1997-2023, Edward K. Ream.
      Last updated on February 28, 2023.
      Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 5.3.0.
    </div>
  </body>
</html>